import { CommonTools } from './CommonTools';
import FairyEditor = CS.FairyEditor;
import CodeWriter from './CodeWriter';
import System = CS.System;
import JsonUtil = CS.FairyEditor.JsonUtil;

function genCode(handler: FairyEditor.PublishHandler) {
    let settings = (<FairyEditor.GlobalPublishSettings>handler.project.GetSettings("Publish")).codeGeneration;
    let codePkgName = handler.ToFilename(handler.pkg.name); //convert chinese to pinyin, remove special chars etc.
    let exportCodePath = handler.exportCodePath + '/' + codePkgName;
//    console.log("<<<<<<<----------settings.ignoreNoname====="+settings.ignoreNoname);
    let classes = handler.CollectClasses(false,false, null);    
    // let classes2 = handler.CollectClasses(settings.ignoreNoname,settings.ignoreNoname, null);   //如果不设置settings.ignoreNoname  会出现 获取的子节点类型不对
    handler.SetupCodeFolder(exportCodePath, "ts"); //check if target folder exists, and delete old files
    
    let allComItems:Map<string,FairyEditor.FPackageItem> = new Map<string,FairyEditor.FPackageItem>();
    //#region-----------------------------------------------包中所有导出的对象---------------------------------------
    let items = handler.items;
    // console.log("---------items======"+items.Count)
    for (let index = 0; index < items.Count; index++) {
        const element = items.get_Item(index);
        if(element.type == "component"){
            allComItems.set(element.name,element);
        }
    }
    //#endregion-----------------------------------------------包中所有导出的对象---------------------------------------

    //#region-----------------------------------------------生成对应的ts文件---------------------------------------
    console.log("----正在发布这个包========"+handler.pkg.name+" codePkgName==="+codePkgName)
    let classCnt = classes.Count;
    let classNameAry:string[] = [];//保存所有需要生成的组件名称
    let writer = new CodeWriter();
    for (let i: number = 0; i < classCnt; i++) {
        let classInfo = classes.get_Item(i);
        let members = classInfo.members;
        let className = classInfo.className;//包里的 组件名称 MainCity
        let superClassName = classInfo.superClassName;//组件类型 GComponent
        if(!allComItems.has(className)){
            console.log("这个类型不生成对应的代码======="+className+"  superClassName==="+superClassName)
            continue;
        }
        let isCom = superClassName === "GComponent";//是否是 组件类型的
        classNameAry.push(className)
        writer.reset();

        console.log("生成 组件==="+className+"=类型="+superClassName);
        writer.writeln('export class %s extends CS.FairyGUI.%s ',className,superClassName) //CS.FairyGUI.GComponent
        //生成 ui 对应的 url 路径
       
        writer.startBlock();
        writer.writeln();
        writer.writeln('static URL: string = "ui://%s%s";', handler.pkg.id, classInfo.resId);  // static URL: string = "ui://b6lak2n9kd357u";
        writer.writeln();
        let memberCnt = members.Count
        //生成 组件中的所有子节点的 变量 声明
        for (let j: number = 0; j < memberCnt; j++) {
            let memberInfo = members.get_Item(j);
            let memberType = memberInfo.type; //对象的类型 GButton
            let memberName = memberInfo.varName;//对象的名称
            if(CommonTools.checkIsFguiType(memberType)){
                writer.writeln('%s: CS.FairyGUI.%s;',memberName, memberType); 
            }else{
                writer.writeln('%s: CS.FairyGUI.GComponent;',memberName); 
            }
            
        }
       
        writer.writeln();


        // 不是 GComponent  类型的都要生成构造函数
        if(!isCom){
            writer.writeln("constructor()");
            writer.startBlock();
            writer.writeln("super();");
            writer.writeln('this.__onConstruct = () => { this.onInit(); };');
            writer.writeln('this.__onDispose = () => {  this.onDispose(); };');

            writer.endBlock();
        }

        //-----------------------------组件中的所有子节点------------------------------------------------------------------------
        //生成函数 onInit  给所有的ui对象赋值 
        writer.writeln();
        writer.writeln("onInit(){")
        
        let memberTypeDic:Map<string,FairyEditor.PublishHandler.MemberInfo[]> = new Map<string,FairyEditor.PublishHandler.MemberInfo[]>;
        for (let j: number = 0; j < memberCnt; j++) {
            let memberInfo = members.get_Item(j);
            let memberType = memberInfo.type; //对象的类型 例如 GButton
            let memberVarName = memberInfo.varName;//对象名称
            let memberName = memberInfo.name;
            
            // console.log("       子节点==="+"=="+memberVarName+"=="+memberName+"=="+memberType)
            if (memberInfo.group == 0) {
                if(CommonTools.checkIsFguiType(memberType)){
                    writer.writeln('    this.%s = <CS.FairyGUI.%s>this.GetChild("%s");',memberVarName, memberType,memberName); 
                }else{
                    writer.writeln('    this.%s = <CS.FairyGUI.GComponent>this.GetChild("%s");',memberVarName,memberName); 
                }
                
                if(!memberTypeDic.has(memberType)){
                    memberTypeDic.set(memberType,new Array<FairyEditor.PublishHandler.MemberInfo>);
                }
                memberTypeDic.get(memberType).push(memberInfo);
            }
            else if (memberInfo.group == 1) {
                writer.writeln('    this.%s = <CS.FairyGUI.Controller>this.GetController("%s");',memberVarName,memberName); //控制器
            }
            else {
                writer.writeln('    this.%s = <CS.FairyGUI.Transition>this.GetTransition("%s");',memberVarName,memberName); //动效
            }
        }

        //生成 按钮的 点击事件 监听
        let allBtnCom = memberTypeDic?.get("GButton") || [];
        for (let j: number = 0; j < allBtnCom.length; j++) {
            let memberInfo = allBtnCom[j];
            let memberVarName = memberInfo.varName;//对象名称

            writer.writeln('    this.%s.onClick.Add(() => {',memberVarName); 
            writer.writeln('        this.onClick%s();',memberVarName); 
            writer.writeln('    });');
        }

        //生成 列表的 渲染 监听
        let allListCom = memberTypeDic?.get("GList") || [];
        for (let j: number = 0; j < allListCom.length; j++) {
            let memberInfo = allListCom[j];
            let memberVarName = memberInfo.varName;//对象名称

            writer.writeln('    this.%s.itemRenderer = (index: number, item: 自己的类型|| CS.FairyGUI.GObject) => {', memberVarName); 
            writer.writeln('        this.render%sItem(index, item);', memberVarName); 
            writer.writeln('    };'); 

            writer.writeln('    this.%s.onClickItem.Add((context: CS.FairyGUI.EventContext) => {', memberVarName); 
            writer.writeln('        this.onClick%sItem(context);', memberVarName); 
            writer.writeln('    });', memberVarName); 
        }

        writer.writeln("};")//onInit end
        if(!isCom){
            //生成函数 onDispose 
            writer.writeln();
            writer.writeln("onDispose()")
            writer.startBlock();
            writer.endBlock();//onDispose end
        }

        //生成 所有 按钮的 点击函数
        for (let j: number = 0; j < allBtnCom.length; j++) {
            let memberInfo = allBtnCom[j];
            let memberVarName = memberInfo.varName;//对象名称

            writer.writeln('onClick%s(){',memberVarName); 
            writer.writeln('};'); 
        }

        //生成所有 列表的 渲染函数 点击函数
        for (let j: number = 0; j < allListCom.length; j++) {
            let memberInfo = allListCom[j];
            let memberVarName = memberInfo.varName;//对象名称

            writer.writeln('render%sItem(index, item){', memberVarName); 
            writer.writeln('};'); 

            writer.writeln('onClick%sItem(context:CS.FairyGUI.EventContext){', memberVarName); 
            writer.writeln('};'); 
        }

        //-----------------------------组件中的所有子节点------------------------------------------------------------------------
    
        writer.endBlock();//class  end
        writer.save(exportCodePath + '/' + className + '.ts');//生成 ui 对应的 ts文件
        //#endregion-----------------------------------------------生成对应的ts文件---------------------------------------
    }

    writer.reset();


   //#region----------------------------------------生成绑定文件 Binder---------------------------------------------------
    let binderName = codePkgName + 'Binder';
    console.log("开始生成绑定文件==== "+binderName);
    writer.writeln('export default class %s',binderName);
    writer.startBlock();

    writer.writeln('static bindAll()');
    writer.startBlock();
    handler.GetItemDesc
  
    for (let i: number = 0; i < classCnt; i++) {
        let classInfo = classes.get_Item(i);
        // console.log("className== "+ classInfo.className);
        writer.writeln('CS.FairyGUI.UIObjectFactory.SetPackageItemExtension(%s.URL, () => { return new %s(); });', classInfo.className, classInfo.className);
    }
    writer.endBlock(); //bindall
    writer.endBlock(); //class

    writer.save(exportCodePath + '/' + binderName + '.ts');//生成对应的 binder 绑定文件
    //#endregion----------------------------------------生成绑定文件 Binder---------------------------------------------------





    //#region-------------------------------------------生成对应的 UIPkg 文件---------------------------------------
    console.log(">>>>>>>>>>>=========开始生成 UIPkg 文件==== <<<<<<<<<<< codePkgName=="+codePkgName);

    let pkgStrs : string[] = [];
    let pkgPath = CommonTools.getUIPkgPath(handler.exportCodePath);
    if(System.IO.File.Exists(pkgPath)){
        let allLineStr = System.IO.File.ReadAllLines(pkgPath);
        for (let index = 0; index < allLineStr.Length; index++) {
            let lineStr = allLineStr.get_Item(index)
            if(lineStr.indexOf('=') != -1){
                let match = lineStr.match(/(\w+)\s*=\s*"([^"]*)"/);//正则匹配 对应的包名
                pkgStrs.push(match[1])
            }
        }
        // let pkgLineStrs = pkgStr.split('\n');
    }
    if(pkgStrs.indexOf(codePkgName) == -1){
        pkgStrs.push(codePkgName);

        writer.reset();
        writer.writeln('export enum UIPkg {');
        for (let i: number = 0; i < pkgStrs.length; i++) {
            let pkgName = pkgStrs[i];
            writer.writeln('    %s = "%s",',pkgName,pkgName);
        }
        writer.writeln('}');
        writer.save(pkgPath);//生成对应的 UIPkg 文件
    }
    console.log("<<<<<<<<<<<=========结束生成 UIPkg 文件==== <<<<<<<<<<< path="+pkgPath);
    //#endregion-------------------------------------------生成对应的 UIPkg 文件---------------------------------------
    






    //#region-------------------------------------------生成对应的 ViewID 文件---------------------------------------
    console.log(">>>>>>>>>>>=========开始生成 ViewID 文件==== <<<<<<<<<<< codePkgName=="+codePkgName);
    let viewPath = CommonTools.getViewIdPath(handler.exportCodePath);
    let viewBagMap : Map<string,string[]> = new Map<string,string[]>();
    if(System.IO.File.Exists(viewPath)){
        //Arena_ArenaLvSelectView_ID = "Arena#ArenaLvSelectView",
        let allLineStr = System.IO.File.ReadAllLines(viewPath);
        for (let index = 0; index < allLineStr.Length; index++) {
            let lineStr = allLineStr.get_Item(index)
            if(lineStr.indexOf('=') != -1){
                let match = lineStr.match(/"([^"]+)"/);//正则匹配 "" 中间的 字符
                let vdic = match[1].split("#");
                let vBagStr = vdic[0];//对应的包
                let vComStr = vdic[1];//对应的组件
                if(!viewBagMap.has(vBagStr)){
                    viewBagMap.set(vBagStr,[])
                }
                viewBagMap.get(vBagStr).push(vComStr)
            }
        }
    }
    if (!viewBagMap.has(codePkgName)) {
        viewBagMap.set(codePkgName, [])
    }
    let viewHasChange = false;
    for (let index = 0; index < classNameAry.length; index++) {
        let name = classNameAry[index];
        if (CommonTools.checkIsViewUI(name)) {
            if (viewBagMap.get(codePkgName).indexOf(name) == -1) {
                viewBagMap.get(codePkgName).push(name)
                viewHasChange = true;
            }
        }
    }
    if (viewHasChange) {
        //Arena_ArenaLvSelectView_ID = "Arena#ArenaLvSelectView",
        writer.reset();
        writer.writeln('export enum ViewID {');
        for (let [kBag, vComAry] of viewBagMap.entries()) {
            for (let index = 0; index < vComAry.length; index++) {
                const comName = vComAry[index];
                writer.writeln('    %s_%s_ID = "%s#%s",', kBag, comName, kBag, comName);
            }
        }
        writer.writeln('}');
        writer.save(viewPath);//生成对应的 ViewID 文件
    }
    
    console.log("<<<<<<<<<<<<<=========结束生成 ViewID 文件==== <<<<<<<<<<< path=="+viewPath);
    //#endregion-------------------------------------------生成对应的 ViewID 文件---------------------------------------







    //#region-------------------------------------------生成对应的UIConst 文件---------------------------------------

    let uiConstPath = CommonTools.getUIConstPath(handler.exportCodePath);
    console.log(">>>>>>>>>>>=========开始生成 UIConst 文件==== <<<<<<<<<<< codePkgName=="+codePkgName);
    let pkgFileMap : Map<string,string[]> = new Map<string,string[]>();//key 包名  value 对应生成的资源文件的名称

    // 获取文件
    let files = System.IO.Directory.GetFiles(handler.exportPath);
    // console.log("获取文件==="+handler.exportPath+"====="+files.Length);
    for (let index = 0; index < files.Length; index++) {
        let file = files.get_Item(index);
        let ext = System.IO.Path.GetExtension(file);
        let fileName = System.IO.Path.GetFileName(file);
        let fileNameSplit = fileName.split("_");
        if (ext != ".meta") {
            let pkgName = fileNameSplit.at(0) ?? "";
            if (pkgName != "") {
                if (!pkgFileMap.has(pkgName)) {
                    pkgFileMap.set(pkgName,[]);
                }
                pkgFileMap.get(pkgName).push(fileName);//资源文件名称
            }
        }
    }
    if(System.IO.File.Exists(uiConstPath)){
        let allLineStr = System.IO.File.ReadAllLines(uiConstPath);
        for (let index = 0; index < allLineStr.Length; index++) {
            let lineStr = allLineStr.get_Item(index)
            if(lineStr.indexOf('||') != -1 && lineStr.indexOf('!') != -1){
                let match = lineStr.match(/"([^"]+)"/);//正则匹配 "" 中间的 字符
                let vpkgStr = match[1];//对应的包名
                if(!pkgFileMap.has(vpkgStr)){
                    pkgFileMap.set(vpkgStr,[])
                }
            }
        }
    }

    if(!pkgFileMap.has(codePkgName)){
        pkgFileMap.set(codePkgName,[])
    }
    writer.reset();
    let baseImportPath = CommonTools.getUIConstImportPath();
    for(let [pkgName,fileAry] of pkgFileMap){
        let str = `import ${pkgName}Binder from "${baseImportPath}${pkgName}/${pkgName}Binder";`
        writer.writeln(str);
    }


    writer.writeln('export class UIConst {');
    writer.writeln();
    
    let pkgFilesMapStr = "";
    let pkgFileMapKeysCount = 0;
    let pkgFileMapKeysMaxCount = pkgFileMap.size;
    for (let [pkgName, fileAry] of pkgFileMap) {
        let pkgOutFiles = "";
        for (let index = 0; index < fileAry.length; index++) {
            let fname = fileAry[index];

            pkgOutFiles += `\t\t\t\t"${fname}"` ;
            if(index != fileAry.length-1){
                pkgOutFiles+=`,\n`;
            }
        }

        pkgFilesMapStr +=`
        [
            "${pkgName}",  //包名
            [
${pkgOutFiles}
            ]
        ]`;
        if(pkgFileMapKeysCount != pkgFileMapKeysMaxCount-1){
            pkgFilesMapStr += ',';
        }
        pkgFileMapKeysCount++;
    }
    let uiConstTemplate = `
    static readonly pkgFiles: Map<string, string[]> = new Map([
%s
    ]);`;
    writer.writeln(uiConstTemplate,pkgFilesMapStr);
    writer.writeln();

   
    let bindFunStr = '';
    let pkgFileMapKeysCount2 = 0;
    let pkgFileMapSize = pkgFileMap.size;
    for(let [pkgName,fileAry] of pkgFileMap){
        bindFunStr+=`\t\t(!pkg || pkg == "${pkgName}") && ${pkgName}Binder.bindAll();`;
        if(pkgFileMapKeysCount2 != pkgFileMapSize-1){
            bindFunStr+=`\n`;
        }
    }
    let bindMapStr = `
    static bind(pkg?: string) {
${bindFunStr}
    }`;
    writer.writeln(bindMapStr);

    writer.writeln('}');// end  UIConst
    writer.save(uiConstPath);//生成对应的 UIConst  文件
    // JsonUtil.DecodeJson()
    console.log("<<<<<<<<<<<<<=========结束生成 UIConst 文件==== <<<<<<<<<<< path=="+uiConstPath);
    //#endregion-------------------------------------------生成对应的UIConst 文件---------------------------------------
}

export { genCode };